import pymysql
import paramiko
import threading
import os
import sys
from fileTest import fileManager as fm
from utils import MySQLMonitor



# ssh工具集, 继承MySQLMonitor类，方便调用生成word报告功能
class SSHTool(MySQLMonitor.MySQLMonitor):
    # 从数据库获取服务器ssh连接信息
    def get_ssh_info_from_MySQL(self):
        try:
            dbconn = pymysql.connect(host='192.168.140.10', user='admin', password='123456', database='it')
        except Exception as e:
            print("数据库连接失败，请检查数据库连接信息")
            print(e)
            sys.exit()
        cr = dbconn.cursor()

        query_sql = "select ip, user, password, port from hosts"
        result = cr.execute(query_sql)
        if result != 0:
            hosts = cr.fetchall()

        cr.close()
        dbconn.close()

        return hosts

    # ssh连接服务器执行命令
    def execCMD(self, ip, user, password, command, port=22):
        ssh_client = paramiko.SSHClient()
        ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        try:
            ssh_client.connect(hostname=ip, port=port, username=user, password=password)
        except Exception as e:
            print("服务器【%s】 ssh连接失败，检查ssh连接信息是否正确" % ip)
            print(e)
            sys.exit()

        stdin, stdout, stderr = ssh_client.exec_command(command)
        result = stdout.read().decode("utf-8")
        print("服务器【%s】执行【%s】操作的结果: " % (ip, command))
        print(result)
        print("---------------" * 8)

        ssh_client.close()

    # 批量执行命令
    def MultiExecCMD(self):
        command = input("执行的操作: ").strip()
        hosts = self.get_ssh_info_from_MySQL()
        for ip, user, password, port in hosts:
            ssh_thread = threading.Thread(target=self.execCMD, args=(ip, user, password, command, port))
            ssh_thread.start()

    # Linux主机运行状态巡检  {"运行指标":"数据"}
    def host_status(self, ip, user, password, port=22):
        status = {"服务器地址": ip}

        ssh_client = paramiko.SSHClient()
        ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        try:
            ssh_client.connect(hostname=ip, port=port, username=user, password=password)
        except Exception as e:
            print("服务器【%s】 ssh连接失败，检查ssh连接信息是否正确" % ip)
            print(e)
            sys.exit()

        # 获取系统内核版本
        stdin, stdout, stderr = ssh_client.exec_command("uname -r")
        kernel_version = stdout.read().decode("utf-8").rstrip("\n")
        status["内核版本"] = kernel_version

        # 获取CPU型号
        stdin, stdout, stderr = ssh_client.exec_command("cat /proc/cpuinfo | grep 'model name' | uniq | awk -F ':' '{print $2}'")
        cpu_model = stdout.read().decode("utf-8").rstrip("\n")
        status["CPU型号"] = cpu_model

        # 获取CPU数量
        stdin, stdout, stderr = ssh_client.exec_command("nproc")
        cpu_num = stdout.read().decode("utf-8").rstrip("\n")
        status["CPU数量"] = cpu_num

        # 获取内存总容量
        stdin, stdout, stderr = ssh_client.exec_command("free -h | grep Mem | awk '{print $2}'")
        memory_total = stdout.read().decode("utf-8").rstrip("\n")
        status["内存总容量"] = memory_total

        ssh_client.close()

        return status

    # 上传文件, server_dir: 服务器目录   /opt   /opt/
    def fileUpload(self, ip, user, password, src_file, server_dir, port=22):
        # 检测源文件是否存在
        if not os.path.exists(src_file):
            print("源文件【%s】不存在，检查文件路径是否正确" % src_file)
            sys.exit()

        # 拼接服务器上完整的文件名称
        if server_dir.endswith("/"):
            server_file_name = server_dir + os.path.basename(src_file)
        else:
            server_file_name = server_dir + "/" + os.path.basename(src_file)

        try:
            sshconn = paramiko.Transport((ip, port))
        except Exception as e:
            print("服务器【%s】ssh连接失败，检查IP地址、端口是否正确" % ip)
            sys.exit()

        try:
            sshconn.connect(username=user, password=password)
        except Exception as e:
            print("服务器【%s】ssh连接失败，检查用户名、密码是否正确" % ip)
            sys.exit()

        sftp = paramiko.SFTPClient.from_transport(sshconn)
        sftp.put(src_file, server_file_name)

        sftp.close()
        sshconn.close()

        return server_file_name


    # ssh连接任意服务器， 获取任意文件MD5校验码
    def file_md5_from_linux(self, ip, user, password, filename, port=22):
        md5_command = "md5sum %s | awk '{print $1}'" % filename

        ssh_client = paramiko.SSHClient()
        ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        try:
            ssh_client.connect(hostname=ip, port=port, username=user, password=password)
        except Exception as e:
            print("服务器【%s】 ssh连接失败，检查ssh连接信息是否正确" % ip)
            print(e)
            sys.exit()

        stdin, stdout, stderr = ssh_client.exec_command(md5_command)
        result = stdout.read().decode("utf-8").strip()

        ssh_client.close()

        return result


    # 批量上传文件
    def MultiUploadFile(self):
        src_file = input("源文件: ").strip()
        server_dir = input("服务器目录: ").strip()

        # 获取源文件的校验码,输出
        src_file_md5 = fm.file_md5(src_file)
        print("源文件[%s]的校验码: %s" % (src_file, src_file_md5))

        print("---------------" * 8)


        hosts = self.get_ssh_info_from_MySQL()
        for ip, user, password, port in hosts:
            # 上传文件
            server_file_name = self.fileUpload(ip=ip, user=user, password=password,
                                               src_file=src_file, server_dir=server_dir, port=port)
            # 获取服务器上文件的校验码
            server_file_md5 = self.file_md5_from_linux(ip=ip, user=user, password=password,
                                                       filename=server_file_name, port=port)
            print("服务器[%s]文件[%s]的校验码: %s" % (ip, server_file_name, server_file_md5))

            if server_file_md5 == src_file_md5:
                print("文件上传成功!!!!!!")
            else:
                print("文件上传失败!!!!!!")

            print("---------------" * 8)

if __name__ == '__main__':
    p1 = SSHTool()
    p1.MultiUploadFile()